// src/services/trading-advisor.service.ts
import * as fs from 'fs';
import * as path from 'path';
import { DeepseekService, DeepseekModel, ChatRole } from './deepseek.service';
import { TelegramBotService } from './telegram-bot.service';
import * as dotenv from 'dotenv';

// 加载环境变量
dotenv.config();

/**
 * 交易顾问服务配置接口
 */
export interface TradingAdvisorConfig {
  logDir?: string;          // 日志目录
  instruments: string[];    // 交易品种列表
}

/**
 * 交易顾问服务
 * 负责生成交易建议并通过Telegram发送
 */
export class TradingAdvisorService {
  private readonly logDir: string;
  private readonly instruments: string[];

  /**
   * 构造函数
   * @param config 交易顾问配置
   */
  constructor(config: TradingAdvisorConfig) {
    this.logDir = config.logDir || path.join(process.cwd(), 'logs');
    this.instruments = config.instruments;
  }

  /**
   * 生成并发送交易建议
   * @param streamOutput 是否使用流式输出，默认为true
   */
  async generateAndSendAdvice(streamOutput: boolean = true): Promise<void> {
    // 检查环境变量
    if (!this.checkEnvironmentVariables()) {
      return;
    }

    try {
      // 读取日志目录下的所有JSON文件
      console.log(`读取日志目录: ${this.logDir}`);

      const files = fs.readdirSync(this.logDir).filter(file => file.endsWith('.json') || file.endsWith('.txt'));
      if (files.length === 0) {
        console.log('没有找到指标日志文件');
        return;
      }

      console.log(`找到 ${files.length} 个指标日志文件`);

      // 读取所有日志文件内容
      const indicatorData: Record<string, any[]> = {};
      const txtData: Record<string, string> = {}; // 用于存储txt文件内容

      for (const file of files) {
        const filePath = path.join(this.logDir, file);
        const content = fs.readFileSync(filePath, 'utf8');

        if (file.endsWith('.json')) {
          // 解析每行JSON
          const lines = content.split('\n').filter(line => line.trim());
          const jsonData = lines.map(line => JSON.parse(line));

          indicatorData[file] = jsonData;
          console.log(`已读取JSON文件 ${file}: ${jsonData.length} 条记录`);
        } else if (file.endsWith('.txt')) {
          // txt文件不解析，直接存储内容
          txtData[file] = content;
          const lineCount = content.split('\n').length;
          console.log(`已读取TXT文件 ${file}: ${lineCount} 行`);
        }
      }

      // 构建AI提示
      const prompt = this.constructAIPrompt(indicatorData, txtData);

      // 初始化DeepSeek服务
      const deepseekService = new DeepseekService();
      console.log('正在请求AI分析...');

      // 根据参数选择使用流式或非流式输出
      const analysis = streamOutput
        ? await this.getStreamAnalysis(deepseekService, prompt)
        : await this.getNonStreamAnalysis(deepseekService, prompt);

      // 发送Telegram通知
      await this.sendTelegramNotification(analysis);

    } catch (error: any) {
      console.error('获取交易建议失败:', error.message);
    }
  }

  /**
   * 发送Telegram通知
   * @param analysis 分析结果
   */
  private async sendTelegramNotification(analysis: string): Promise<void> {
    if (!process.env.TELEGRAM_CHAT_ID) {
      console.log('未设置TELEGRAM_CHAT_ID，跳过发送通知');
      console.log('分析结果:');
      console.log(analysis);
      return;
    }

    const telegramBot = new TelegramBotService();
    const chatId = process.env.TELEGRAM_CHAT_ID;

    // 准备消息标题
    const instruments = this.instruments.join(', ');
    const title = `🤖 <b>${instruments} 技术指标分析</b>\n\n`;

    // 对AI生成的文本进行HTML转义，防止解析错误
    const sanitizedAnalysis = this.escapeHtml(analysis);

    // 发送分析结果
    if (sanitizedAnalysis.length <= 4000) {
      await telegramBot.sendMessage(
        chatId,
        title + sanitizedAnalysis,
        { parseMode: 'HTML' }
      );
      console.log('分析结果已发送到Telegram');
    } else {
      // 如果内容太长，分段发送
      console.log('分析结果超过4000字符，分段发送...');

      // 发送标题消息
      await telegramBot.sendMessage(
        chatId,
        title + '(分多条消息发送)',
        { parseMode: 'HTML' }
      );

      // 分段发送内容
      const chunkSize = 3800;
      let start = 0;
      let part = 1;

      while (start < sanitizedAnalysis.length) {
        const chunk = sanitizedAnalysis.substring(start, start + chunkSize);
        await telegramBot.sendMessage(
          chatId,
          `第 ${part} 部分:\n\n${chunk}`,
          { parseMode: 'HTML' }
        );

        start += chunkSize;
        part++;

        // 添加简短延迟避免消息被限流
        if (start < sanitizedAnalysis.length) {
          await new Promise(resolve => setTimeout(resolve, 500));
        }
      }

      console.log(`分析结果已全部发送到Telegram (共 ${part - 1} 部分)`);
    }
  }

  /**
   * 对文本进行HTML转义，以安全地在Telegram的HTML模式下显示
   * @param text 要转义的文本
   * @returns 转义后的文本
   */
  private escapeHtml(text: string): string {
    return text
      .replace(/&/g, "&amp;")
      .replace(/</g, "&lt;")
      .replace(/>/g, "&gt;");
  }

  /**
   * 检查必要的环境变量是否已设置
   */
  private checkEnvironmentVariables(): boolean {
    const requiredVars = [
      'DEEPSEEK_API_KEY',
      'TELEGRAM_BOT_TOKEN',
      'TELEGRAM_CHAT_ID'
    ];

    const missing = requiredVars.filter(varName => !process.env[varName]);

    if (missing.length > 0) {
      console.error(`错误: 以下环境变量未设置: ${missing.join(', ')}`);
      console.error('请在.env文件中设置这些变量');
      return false;
    }

    return true;
  }

  /**
   * 构建AI分析提示
   */
  private constructAIPrompt(indicatorData: Record<string, any[]>, txtData: Record<string, string>): string {
    let prompt = `请基于以下技术指标数据进行分析，并给出交易建议：\n\n`;

    // 添加当前时间
    prompt += `当前时间: ${new Date().toISOString()} (UTC)\n\n`;

    // 添加每个指标文件的内容
    for (const [filename, data] of Object.entries(indicatorData)) {
      // 提取指标名称和交易对信息
      const fileInfo = path.basename(filename, '.json').split('_');
      const indicatorType = fileInfo[0];
      const timeframe = fileInfo[1] || '';
      const symbol = fileInfo.slice(2).join('_');

      prompt += `## ${indicatorType} 指标 (${timeframe} 周期, ${symbol})\n`;

      // 只使用最近的5条记录减少提示长度
      // const recentData = data.slice(0, 10);
      for (const item of data) {
        prompt += `- 时间: ${item.timestamp}, 价格: ${item.price}\n`;
        prompt += `  指标值: ${JSON.stringify(item.indicator)}\n`;
        if (item.signal) {
          prompt += `  信号: ${item.signal}\n`;
        }
        prompt += '\n';
      }
      prompt += '\n';
    }

    // 添加txt文件内容作为提示的一部分
    for (const [filename, content] of Object.entries(txtData)) {
      // 从文件名中提取信息
      const fileBasename = path.basename(filename, '.txt');
      const filenameParts = fileBasename.split('_');

      if (filenameParts[0] === 'Kline' && filenameParts.length >= 3) {
        const coin = filenameParts[1];
        const period = filenameParts[2];

        prompt += `## K线数据 (${period} 周期, ${coin})\n`;

        // 从内容中提取数据：跳过标题行，只取最近的5条记录
        const lines = content.split('\n').filter(line => line.trim());
        const header = lines[0]; // 保存标题行

        if (lines.length > 1) {
          prompt += `标题: ${header}\n\n`;

          // 只取最新的5条记录（假设数据是按时间顺序排列的）
          const recentLines = lines.slice(Math.max(1, lines.length - 5));

          for (const line of recentLines) {
            prompt += `${line}\n`;
          }

          prompt += `\n总共 ${lines.length - 1} 条K线记录，以上展示最近10条\n`;
        } else {
          prompt += `文件为空或仅包含标题行\n`;
        }
      } else {
        // 对于其他txt文件，显示文件名和一个简短摘要
        prompt += `## 文件: ${fileBasename}\n`;
        const lines = content.split('\n').filter(line => line.trim());
        prompt += `文件包含 ${lines.length} 行数据，前3行预览:\n`;
        for (let i = 0; i < Math.min(3, lines.length); i++) {
          prompt += `${lines[i]}\n`;
        }
      }

      prompt += '\n';
    }

    prompt += `请提供以下内容：
1. 各指标的市场趋势分析（上涨、下跌或震荡）
2. 主要支撑位和阻力位
3. 综合各指标分析，是否建议开单？如果建议，应该做多还是做空？
4. 建议的入场价格区间
5. 止盈目标位（至少2个目标）
6. 止损位置
7. 风险评估（低、中、高）
8. 交易理由和技术指标依据

我提供的信息中包含交易策略.txt文件，请着重参考该文件中的内容，但并不代表要完全遵守其中的策略，请根据实际情况进行判断。
请用简洁明了的语言回答，并确保建议具体且可操作。`;

    console.log(`构建的AI提示长度: ${prompt.length} 字符`);
    return prompt;
  }

  /**
   * 获取流式分析结果
   * @param deepseekService DeepSeek服务实例
   * @param prompt 提示内容
   * @returns 完整的分析结果
   */
  private async getStreamAnalysis(deepseekService: DeepseekService, prompt: string): Promise<string> {
    return new Promise<string>((resolve, reject) => {
      let fullContent = '';
      let lastOutputLength = 0;
      const updateInterval = 50; // 控制输出频率，单位为毫秒
      let lastUpdateTime = 0;

      // 使用流式API
      deepseekService.chatStream(
        [
          {
            role: ChatRole.SYSTEM,
            content: '你是一个专业的量化交易分析师，擅长技术分析和价格预测。请基于多个技术指标的数据提供清晰、具体的交易建议，包括入场点位、止盈止损位置、合约倍数和理由。'
          },
          { role: ChatRole.USER, content: prompt }
        ],
        (content: string, done: boolean) => {
          // 更新完整内容
          fullContent = content;

          // 控制输出频率，避免刷屏太快
          const now = Date.now();
          if (done || now - lastUpdateTime >= updateInterval) {
            // 只输出新增内容
            if (content.length > lastOutputLength) {
              const newContent = content.substring(lastOutputLength);
              process.stdout.write(newContent);
              lastOutputLength = content.length;
            }

            lastUpdateTime = now;
          }

          // 在完成时返回结果
          if (done) {
            console.log('\n\n分析完成！');
            resolve(fullContent);
          }
        },
        DeepseekModel.REASONER,
        {
          temperature: 1.0,
        }
      ).catch(reject);
    });
  }

  /**
   * 获取非流式分析结果
   * @param deepseekService DeepSeek服务实例
   * @param prompt 提示内容
   * @returns 完整的分析结果
   */
  private async getNonStreamAnalysis(deepseekService: DeepseekService, prompt: string): Promise<string> {
    const analysis = await deepseekService.chat(
      [
        {
          role: ChatRole.SYSTEM,
          content: '你是一个专业的量化交易分析师，擅长技术分析和价格预测。请基于多个技术指标的数据提供清晰、具体的交易建议，包括入场点位、止盈止损位置和理由。'
        },
        { role: ChatRole.USER, content: prompt }
      ],
      DeepseekModel.REASONER,
      {
        temperature: 1.0,
      }
    );

    console.log('已获取AI分析结果');
    return analysis;
  }
} 